﻿using System;
using System.Linq;
using System.Runtime.InteropServices;

namespace Btstack
{
    public class Gap
    {
        public const byte GAP_EVENT_SECURITY_LEVEL = 0xE0;
        public const byte GAP_EVENT_DEDICATED_BONDING_COMPLETED = 0xE1;
        public const byte GAP_EVENT_ADVERTISING_REPORT = 0xE2;
        public const byte GAP_EVENT_INQUIRY_RESULT = 0xE3;
        public const byte GAP_EVENT_INQUIRY_COMPLETE = 0xE4;
        public const byte GAP_EVENT_RSSI_MEASUREMENT = 0xE5;

        [DllImport("btstack-c.dll", EntryPoint = "gap_local_bd_addr")]
        private static extern void LocalBdAddr(IntPtr address_buffer);

        [DllImport("btstack-c.dll", EntryPoint = "gap_set_connection_parameters")]
        public static extern void SetConnectionParameters(ushort conn_scan_interval, ushort conn_scan_window,
            ushort conn_interval_min, ushort conn_interval_max, ushort conn_latency,
            ushort supervision_timeout, ushort min_ce_length, ushort max_ce_length);

        [DllImport("btstack-c.dll", EntryPoint = "gap_connect")]
        private static extern byte Connect(IntPtr addr, Btstack.BdAddrType type);

        [DllImport("btstack-c.dll", EntryPoint = "gap_set_scan_parameters")]
        public static extern void SetScanParameters(byte type, ushort interval, ushort window);

        [DllImport("btstack-c.dll", EntryPoint = "gap_start_scan")]
        public static extern void StartScan();

        [DllImport("btstack-c.dll", EntryPoint = "gap_stop_scan")]
        public static extern void StopScan();

        [DllImport("btstack-c.dll", EntryPoint = "gap_disconnect")]
        public static extern byte Disconnect(ushort handle);

        public static byte[] LocalBdAddr()
        {
            IntPtr pnt = Marshal.AllocHGlobal(6);

            LocalBdAddr(pnt);

            var addr = new byte[6];

            Marshal.Copy(pnt, addr, 0, 6);

            Marshal.FreeHGlobal(pnt);

            return addr;
        }

        public static string LocalBdAddrStr(string separator = ":")
        {
            return BitConverter.ToString(LocalBdAddr()).Replace("-", separator);
        }

        public static Btstack.BdAddrType EeventAdvertisingReportGetAddressType(byte[] packet)
        {
            return (Btstack.BdAddrType)packet[3];
        }

        public static byte[] EventAdvertisingReportGetAddress(byte[] packet)
        {
            var addr = packet.Skip(4).Take(6).ToArray();
            Array.Reverse(addr);
            return addr;
        }

        public static string EventAdvertisingReportGetAddressStr(byte[] packet, string separator = ":")
        {
            return BitConverter.ToString(EventAdvertisingReportGetAddress(packet)).Replace("-", separator);
        }

        public static byte Connect(byte[] addr, Btstack.BdAddrType type)
        {
            IntPtr AddrPtr = Marshal.AllocHGlobal(6);
            Marshal.Copy(addr, 0, AddrPtr, 6);
            var ret = Connect(AddrPtr, type);
            Marshal.FreeHGlobal(AddrPtr);
            return ret;
        }

        public static byte Connect(string addr, Btstack.BdAddrType type)
        {
            addr = addr.Replace("-", "").Replace(":", "").Replace(" ", "");

            var AddrBytes = new byte[6];

            for (int i = 0; i < addr.Length; i++)
            {
                try
                {
                    AddrBytes[i] = Convert.ToByte(addr.Substring(i * 2, 2), 16);
                }
                catch
                {
                    break;
                }
            }

            IntPtr AddrPtr = Marshal.AllocHGlobal(6);
            Marshal.Copy(AddrBytes, 0, AddrPtr, 6);
            var ret = Connect(AddrPtr, type);
            Marshal.FreeHGlobal(AddrPtr);
            return ret;
        }

        public static string AdvertisementReportName(byte[] packet)
        {
            var adv_data = packet.Skip(12).Take(packet[11]).ToArray();

            while (adv_data.Length > 0)
            {
                byte data_type = adv_data[1];
                int size = adv_data[0] - 1;
                var data = adv_data.Skip(2).Take(size).ToArray();

                switch (data_type)
                {
                    case Btstack.BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
                    case Btstack.BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
                        return System.Text.Encoding.Default.GetString(data);
                }

                adv_data = adv_data.Skip(2 + size).ToArray();
            }

            return "";
        }
    }
}
